﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AwpAdminTool;
using System.Net.Battlefield3;
using System.IO;
using Microsoft.VisualBasic.FileIO;

namespace AwpAdminConsole
{
    class Program
    {
        static AwpAdmin AdminClient;
        static StreamWriter logger;
        static void Main(string[] args)
        {
            Write("AwpAdmin Launching.");

            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            bool autoConnect = false;

            //check args
            if (args.Length > 0)
            {
                for (int i = 0; i < args.Length; i++)
                {
                    switch (args[i])
                    {
                        case "-settings":
                            if (args.Length > i + 1) //next arg exists
                            {
                                i++; //increment because reading to next arg
                                if (Directory.Exists(args[i]))
                                    AdminClient = new AwpAdmin(args[i]);
                            }
                            break;

                        case "-autoconnect":
                            autoConnect = true;
                            break;
                    }
                }
            }

            if (AdminClient == null) AdminClient = new AwpAdmin(); //default dir

            //set title
            Console.Title = string.Format("AwpAdmin {0}: {1}:{2}",
                System.Reflection.Assembly.GetExecutingAssembly().GetName().Version, AdminClient.Client.Address, AdminClient.Client.Port);

            //events
            AdminClient.Client.Connected += new EventHandler(Client_Connected);
            AdminClient.Client.LoggedOn += new EventHandler(Client_LoggedOn);
            AdminClient.Client.ConnectError += new EventHandler<ConnectErrorEventArgs>(Client_ConnectError);
            AdminClient.Client.Disconnected += new EventHandler<DisconnectedEventArgs>(Client_Disconnected);
            AdminClient.Client.PlayerChat += new EventHandler<PlayerChatEventArgs>(Client_PlayerChat);
            AdminClient.Client.PunkBusterMessage += new EventHandler<PunkBusterMessageEventArgs>(Client_PunkBusterMessage);

            //logger
            logger = new StreamWriter(AdminClient.WorkingDirectory + "log.txt", true);

            if (autoConnect)
            {
                Write("Connecting to server.");
                AdminClient.Client.Connect();
            }

            Write("Launched.");

            //read loop
            //this code is just temporary in order to get a version of AWP. dont worry about validation for now
            string line = "";
            while (line != "exit")
            {
                line = Console.ReadLine();
                if (line == "") continue;

                TextFieldParser parser = new TextFieldParser(new StringReader(line))
                {
                    HasFieldsEnclosedInQuotes = true,
                    Delimiters = new string[] { " ", "\t" }
                };

                string[] fields = parser.ReadFields();


                if (AdminClient.Client.IsLoggedOn)
                {
                    switch (fields[0])
                    {
                        case "players":
                            if (AdminClient.Client.Players.Count == 0)
                            {
                                Write("No players.");
                                break;
                            }

                            PlayerCollection players = AdminClient.Client.Players;
                            foreach (var p in players)
                            {
                                Write("Name: {0} || Team: {1} || Admin: {2}", p.Name, p.TeamId, p.IsAdmin());
                            }

                            Write("{0} total players.", players.Count());
                            break;

                        case "setadmin":
                            PlayerCollection players2 = AdminClient.Client.Players;
                            if (players2.PlayerExists(fields[1]))
                            {
                                Player p = players2[fields[1]];

                                p.GetAdmin().Rank = Convert.ToInt32(fields[2]);
                            }
                            else Write("{0} not found.", fields[1]);
                            break;

                        case "setcommand":
                            AdminClient.SetCommandAccessLevel(fields[1], Convert.ToInt32(fields[2]));
                            break;

                        case "getcommand": //get commands are here for debugging namespaces
                            Write("{0} Access Level: {1}", fields[1], AdminClient.GetCommandAccessLevel(fields[1]));
                            break;

                        case "getadmin":
                            PlayerCollection players3 = AdminClient.Client.Players;
                            if (players3.PlayerExists(fields[1]))
                            {
                                Write("{0} Admin Rank: {1}", fields[1], players3[fields[1]].GetAdmin().Rank);
                            }
                            else Write("{0} not found.", fields[1]);
                            break;

                        case "assemblies":
                            foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
                            {
                                Write("Assembly: {0}", a.FullName);
                            }
                            break;

                        case "say":
                            AdminClient.Client.SendRequest("admin.say", "[Console] " + string.Join(" ", fields, 1, fields.Length - 1), "all");
                            break;

                        case "plugins":
                            StringBuilder plugins = new StringBuilder();
                            foreach (var p in AdminClient.Plugins.Plugins.Keys)
                            {
                                plugins.AppendFormat("{0}, ", p);
                            }
                            Write("Plugins: {0}", plugins.ToString());
                            break;
                    }
                }
                else if (fields[0] == "connect") AdminClient.Client.Connect(); 
            }
        }

        static void Client_PlayerChat(object sender, PlayerChatEventArgs e)
        {
            Write("[{0}] {1}", e.Player == null ? "Admin" : e.Player.Name, e.Message);
        }

        static void Client_PunkBusterMessage(object sender, PunkBusterMessageEventArgs e)
        {
            Write(e.Message.TrimEnd('\r', '\n'));
        }

        static void Client_Connected(object sender, EventArgs e)
        {
            Write("Connected");
        }

        static void Client_Disconnected(object sender, DisconnectedEventArgs e)
        {
            if (e.SocketError == System.Net.Sockets.SocketError.Success)
            {
                Write("Disconnected.");
            }
            else
            {
                Write("Disconnected through SocketException ({0}): {1}", e.SocketError, e.Message);
            }
            AdminClient.Client.Connect();
        }

        static void Client_ConnectError(object sender, ConnectErrorEventArgs e)
        {
            Write("Connection Error Code {0}: {1}", e.SocketError, e.Message);
            Environment.Exit(0);
        }

        static void Client_LoggedOn(object sender, EventArgs e)
        {
            Write("Logged on.");
        }

        //if the logger isnt up, store messages
        static Queue<string> messages = new Queue<string>();

        static void Write(string format, params object[] arg)
        {
            string timeStamp = string.Format("[{0}] ", DateTime.Now.ToString("T"));
            Console.Write(timeStamp);
            Console.WriteLine(format, arg);

            //check message queue
            if (messages.Count > 0)
            {
                foreach (var m in messages)
                {
                    logger.WriteLine(m);
                }
                messages.Clear();
            }

            //log to file:
            if (logger != null)
            {
                logger.Write(timeStamp);
                logger.WriteLine(format, arg);
                logger.Flush();
            }
            else messages.Enqueue(timeStamp + string.Format(format, arg));

        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Write("An unhandled exception has occurred:");
            Write(e.ExceptionObject.ToString());
        }
    }
}
